// 处理HC-SR04超声波传感器的回声信号，并计算距离
//   Description  ﹕超声波检测距离模块
// 本模块理论测试距离 2cm~510cm
// 输出结果保留两位小数
module 	hc_sr_echo(
    input wire Clk				,        // 输入50MHz时钟信号
    input wire clk_us			,     	// 输入1MHz系统时钟信号
    input wire Rst_n			,      // 输入复位信号，低电平有效
    
    input wire echo				,       // 输入超声波回声信号
    output wire [18:0] data_o  		// 输出检测到的距离，以厘米为单位，保留三位小数
);
/* 		S(um) = 17 * t 		-->  x.abc cm	*/
//Parameter Declarations
	parameter T_MAX = 16'd60_000; // 定义计数器的最大值，对应510厘米

	reg r1_echo, r2_echo			;  // 用于边沿检测的寄存器
	wire echo_pos, echo_neg			;  // 回声信号的上升沿和下降
	

	reg [15:0] cnt					;  // 1MHz时钟下的计数器，用于测量回声脉冲宽度
	wire add_cnt					;  // 计数器使能信号
	wire end_cnt					;  // 计数器结束信号
	
	reg [18:0] data_r				;  // 距离数据的中间寄存器

	// 逻辑描述
	// 使用50MHz时钟检测回声信号的边沿，以避免使用1MHz时钟导致的2us延时
	always @(posedge Clk or negedge Rst_n)begin  
		if(!Rst_n)begin  
			r1_echo <= 1'b0;
			r2_echo <= 1'b0;
		end  
		else begin  
			r1_echo <= echo;
			r2_echo <= r1_echo;
		end  
	end

	// 产生上升沿和下降沿信号
	assign echo_pos = r1_echo & ~r2_echo	;  // 回声信号上升沿
	assign echo_neg = ~r1_echo & r2_echo	;  // 回声信号下降沿
	
	// 计数器逻辑，用于测量回声脉冲宽度
	always @(posedge clk_us or negedge Rst_n)begin  
		if(!Rst_n)begin  
			cnt <= 'd0; 
		end 
		else if(add_cnt)begin  
			if(end_cnt)begin  
				cnt <= cnt;  // 如果达到最大测量范围，则保持当前计数值
			end  
			else begin  
				cnt <= cnt + 1'b1; // 否则计数器递增
			end  
		end  
		else begin  // 如果回声信号低电平，计数器归零
			cnt <= 'd0;  
		end  
	end 
	
	assign add_cnt = echo; // 赋值计数器使能信号，当回声信号为高电平时使能计数器
	assign end_cnt = add_cnt && cnt >= T_MAX - 1; //赋值计数器结束信号，当计数器达到最大值T_MAX时有效 超出最大测量范围则保持不变，极限

	// 测试距离=(高电平时间*声速(340M/S))/2;
	// 距离数据处理逻辑，将计数值转换为距离
	always @(posedge Clk or negedge Rst_n) begin  
	    if(!Rst_n) begin  
	        data_r <= 'd2;  // 复位时中间寄存器置为2，用于小数点后三位的计算
	    end 
	    else if(echo_neg) begin  
	        // 当回声信号下降沿到来时，将计数值左移四位并加上自身，实现小数点后三位的计算
			//t = cnt*1000ns = cnt*10-6s
			//s = 340*t m
	        data_r <= (cnt << 4) + cnt;
	    end 
	    else begin  
	        data_r <= data_r;  // 否则保持当前值
	    end  
	end 

	// 将中间寄存器的数据右移一位，实现除以2的操作，得到最终的距离数据
	assign data_o = data_r >> 1;

endmodule 

